﻿namespace _4InARow
{
    using System;
    using System.Collections.Generic;
    using System.Text;
    using _4InARowUI;

    public class ConsoleInterface
    {
        public const string k_MessageGreet = "Hello! Welcome to 4 in a row game";
        public const string k_EnterWidth = "Please enter the width of the board (minimum {0}, maximum {1})";
        public const string k_EnterHeight = "Please enter the height of the board (minimum {0}, maximum {1})";
        public const string k_DimensionsOutOfLimit = "Dimensions are out of limits.";
        public const string k_ChooseType = "Please choose the type of player 2 (1 - Human, 2 - Compuer)";
        public const string k_PlayerWon = "Player {0} won!";
        public const string k_BoardFull = "Board is full! It's a tie!";
        public const string k_Rematch = "Match is over. Rematch? (Y/N)";
        public const string k_Goodbye = "Thank you for playing, goodbye";
        public const string k_PickColumn = "Player {0}, please pick a column: ";
        public const string k_ShowScore = "_,.-+=* Score status: Player 1 - {0}    Player 2 - {1} *=+-.,_";
        public const string k_PressKey = "Press any key to exit...";

        private LoginForm m_GameWinLogic;
        private TableForm m_GameBoardLogic;

        public ConsoleInterface()
        {
            m_GameWinLogic = new LoginForm();
        }

        public void StartNewGame()
        {
            m_GameWinLogic.ShowDialog();
            startNewMatch();
        }

        private void initBoard()
        {
            uint width, hight;
            getBoardSizes(out width, out hight);
            m_GameBoardLogic.InitTableSizes(width, hight);
        }

        private void getBoardSizes(out uint io_Width, out uint io_Hight)
        {
            io_Width = m_GameWinLogic.RowsSize;
            io_Hight = m_GameWinLogic.ColsSize;
        }

        private Player.ePlayerType askForPlayer2Type()
        {
            Player.ePlayerType result = Player.ePlayerType.Computer;

            if (m_GameWinLogic.IsHumanPlayer)
            {
                result = Player.ePlayerType.Human;
            }
            return result;
        }

        private void startNewMatch()
        {
            bool matchIsNotOver = true;
            bool playerWon = false;
            bool playAgain = false;

            initBoard();
            //resetCurrentPlayer();

            while (matchIsNotOver)
            {
                if (m_GameBoardLogic.IsFull())
                {
                    declareTieMatch();
                    matchIsNotOver = false;
                    continue;
                }

                makeTurnOfCurrentPlayer(out playerWon);

                if (playerWon)
                {
                    decalrePlayerWonMatch(string.Format(k_PlayerWon, m_GameBoardLogic.CurrentPlayerNumber));
                    m_GameBoardLogic.CurrentPlayer.RaisePlayerScore();
                    matchIsNotOver = false;
                    continue;
                }

                m_GameBoardLogic.ChangeCurrentPlayer();
            }

            showScoreStatus(m_GameBoardLogic.Player1, m_GameBoardLogic.Player2);
            playAgain = askForRematch();

            if (playAgain)
            {
                startNewMatch();
            }
            else
            {
                endGame();
            }
        }

        private void makeTurnOfCurrentPlayer(out bool PlayerWonAfterTurn)
        {
            bool playerPlayedHisTurn = false;

            do
            {
                playerPlayedHisTurn = makeTurn(m_GameBoardLogic.CurrentPlayer, out PlayerWonAfterTurn);
            } 
            while (!playerPlayedHisTurn);
        }

        private bool makeTurn(Player i_Player, out bool PlayerWonAfterTurn)
        {
            uint? newColumn = null, newRow = null;
            string errorMessage = string.Empty;
            bool turnEndedOk = false;
            PlayerWonAfterTurn = false;

            m_GameBoardLogic.PrintBoard;

            turnEndedOk = makeMove(i_Player, out newColumn, out newRow, out errorMessage);

            //if (turnEndedOk && newColumn != null && newRow != null)
            //{
                PlayerWonAfterTurn = m_GameBoardLogic.CheckIfCurrentPlayerWon((uint)newColumn, (uint)newRow);
            //}
            //else
            //{
            //    alertTurnWasCancelled(errorMessage);
            //}

            //clearScreen();
            m_GameBoardLogic.PrintBoard;

            return turnEndedOk;
        }

        private bool makeMove(Player i_Player, out uint? o_NewMoveColumn, out uint? o_NewMoveRow, out string o_ErrorMsg)
        {
            o_NewMoveColumn = o_NewMoveRow = null;
            o_ErrorMsg = string.Empty;
            bool successMove = false;
            uint newMoveColumn;

            switch (i_Player.Type)
            {
                case Player.ePlayerType.Human:
                    askToPickColumn(out newMoveColumn);
                    o_NewMoveRow = m_GameBoardLogic.FindRowInAvailableMovesByColumn(newMoveColumn);
                    o_NewMoveColumn = newMoveColumn;
                    break;
                case Player.ePlayerType.Computer:
                    m_GameBoardLogic.MakeAutomaticMove(i_Player, out o_NewMoveColumn, out o_NewMoveRow);
                    break;
            }

            //if (o_NewMoveColumn != null && o_NewMoveRow != null)
            //{
                successMove = m_GameBoardLogic.SetSquareOnBoard(i_Player, (uint)o_NewMoveColumn, (uint)o_NewMoveRow, out o_ErrorMsg);
            //}
            //else
            //{
            //    o_ErrorMsg = Board.k_ErrorIllegalMove;
            //}

            return successMove;
        }

        private void declareTieMatch()
        {
            m_GameBoardLogic.PopUpMsg(k_BoardFull);
        }

        private void decalrePlayerWonMatch(string i_Message)
        {
            m_GameBoardLogic.PopUpMsg(i_Message);
        }

        private bool askForRematch()
        {
            return m_GameBoardLogic.Rematch;
        }

        private void endGame()
        {
            m_GameBoardLogic.PopUpMsg(k_Goodbye);
        }

        //~~~~~~~~STOPPED HERE~~~~~~~~~~//
        private void askToPickColumn(out uint o_Column)
        {
            bool goodInput = false;
            bool quitAfterAnswer = false;
            string userInput = string.Empty;
            o_Column = 0;

            do
            {
                Console.WriteLine(string.Format(k_PickColumn, m_GameLogic.CurrentPlayerNumber));
                userInput = Console.ReadLine();
                if (userInput.ToLower().Equals("q"))
                {
                    goodInput = true;
                    quitAfterAnswer = true;
                }
                else if (uint.TryParse(userInput, out o_Column))
                {
                    goodInput = true;
                }
            } 
            while (!goodInput);

            if (quitAfterAnswer == true)
            {
                endGame();
            }
        }

        private void printBoard(Board i_Board)
        {
            StringBuilder boardScreen = new StringBuilder();

            for (uint i = 1; i <= i_Board.Width; i++)
            {
                boardScreen.Append(string.Format("  {0} ", i));
            }

            boardScreen.AppendLine();

            for (uint i = 0; i < i_Board.Height; i++)
            {
                for (uint j = 0; j < i_Board.Width; j++)
                {
                    boardScreen.Append(string.Format("| {0} ", i_Board.GetCharBySquare(j + 1, i + 1)));
                }

                boardScreen.Append('|');
                boardScreen.AppendLine();
                string separatorsLine = new string('=', ((int)i_Board.Width * 4) + 1);
                boardScreen.AppendLine(separatorsLine);
            }

            Console.WriteLine(boardScreen);
        }

        private void clearScreen()
        {
            Console.Clear();
        }

        private void showScoreStatus(Player i_Player1, Player i_Player2)
        {
            Console.WriteLine(string.Format(k_ShowScore, i_Player1.Score, i_Player2.Score));
        }

        private void alertTurnWasCancelled(string i_Message)
        {
            Console.WriteLine(i_Message);
            pressAnyKey();
        }

        private void pressAnyKey()
        {
            Console.WriteLine(k_PressKey);
            Console.ReadKey();
        }
    }
}
